package edu.maping.easy.fisica;

import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jbox2d.common.Vec2;

import processing.core.PApplet;
import controlP5.ControlEvent;
import controlP5.ControlGroup;
import controlP5.ControlP5;
import controlP5.Controller;
import controlP5.Radio;
import controlP5.Slider;
import ddf.minim.analysis.FFT;
import edu.maping.easy.ControlFacade;
import edu.maping.easy.gui.GUIEvent;
import edu.maping.easy.gui.GuiFactory;
import edu.maping.easy.io.KeyBoardInteraction;
import edu.maping.easy.minim.FFTFacade;
import edu.maping.easy.model.GUIInteraction;
import edu.maping.easy.model.EasyMappingPlugin;
import edu.maping.easy.model.MouseInteraction;
import edu.maping.easy.model.PhysicPolyThing;
import edu.maping.easy.model.Point;
import edu.maping.easy.model.PolygonThing;
import edu.maping.easy.model.Thing;
import edu.maping.easy.model.World;
import fisica.FBlob;
import fisica.FBody;
import fisica.FBox;
import fisica.FCircle;
import fisica.FPoly;
import fisica.FWorld;
import fisica.Fisica;

public class EasyMappingFisica implements EasyMappingPlugin, GUIInteraction,
		MouseInteraction {

	public FWorld world = null;
	ControlP5 controlP5;

	Float density = 10F;
	Float restitutions = 0.5F;
	Float isStatic = 0F;

	Map<String, Float> controllers = new HashMap<String, Float>();

	PApplet pApplet = null;

	boolean started = false;

	Map<Thing, EasyMappingFPoly> thingPolyRelations = new HashMap<Thing, EasyMappingFPoly>();
	Map<EasyMappingFPoly, Thing> polyThingRelations = new HashMap<EasyMappingFPoly, Thing>();

	FBox top = null;

	public FFTFacade fftFacade;

	public void start(World world, PApplet pApplet, ControlP5 controlP5) {
		this.controlP5 = controlP5;
		this.pApplet = pApplet;

		ArrayList<Thing> things = world.getWorld();
		for (Thing thing : things) {
			if (thing instanceof PolygonThing) {

				PolygonThing physicPolyThing = (PolygonThing) thing;

				EasyMappingFPoly fPoly = new EasyMappingFPoly();

				fPoly.setRestitution(restitutions);
				fPoly.setDensity(density);

				fPoly.setStatic(true);

				fPoly.setNoFill();

				for (Point p : physicPolyThing.vertex) {
					fPoly.vertex(p.x, p.y);
				}

				this.world.add(fPoly);

				thingPolyRelations.put(thing, fPoly);
				polyThingRelations.put(fPoly, thing);
			}
		}

		started = true;
	}

	public ArrayList<Thing> contacted = new ArrayList<Thing>();

	public void startCollision(FBody body1, FBody body2) {
		Thing thing = getThingBody(body1, body2);
		if (thing != null) {
			int index = contacted.indexOf(thing);
			if (index < 0) {
				contacted.add(thing);
			}
		}
	}

	public void endCollision(FBody body1, FBody body2) {
//		Thing thing = getThingBody(body1, body2);
//		if (thing != null) {
//			int index = contacted.indexOf(thing);
//			if (index >= 0) {
//				contacted.remove(thing);
//			}
//		}
	}

	private Thing getThingBody(FBody body1, FBody body2) {
		Thing thing = polyThingRelations.get(body1);
		if (thing != null) {
			return thing;
		} else {
			thing = polyThingRelations.get(body2);
			if (thing != null) {
				return thing;
			}
		}
		return null;
	}

	public void draw(PApplet pApplet) {

		if (started) {
			top.setPosition(pApplet.width / 2, -5);
			top.setWidth(pApplet.width);
			if ((pApplet.frameCount % 20) == 1) {
				addBubble(pApplet);
			}

			FFT fft = fftFacade.getFft();

			float avg = fft.calcAvg(0, fft.avgSize() - 1);

			float step = avg / 1024F;
			if (step < 0.01) {
				step = 0.01F;
			} else if (step > 0.8) {
				step = 0.8F;
			}

			world.step(step);

			float x = 0;
			float y = 0;

			// for (EasyMappingFPoly fPoly : thingPolyRelations.values()) {
			//
			// if (!fPoly.isStatic()) {
			// x = fPoly.getX();
			// y = fPoly.getY();
			//
			// Thing thing = polyThingRelations.get(fPoly);
			// if (thing instanceof PhysicPolyThing) {
			// PhysicPolyThing physicPolyThing = (PhysicPolyThing) thing;
			// fPoly.preDraw(pApplet.g);
			// List<Point> points = fPoly.getVertices();
			// List<Point> points2 = physicPolyThing.vertex;
			// for (int i = 1; i < points.size(); i++) {
			// Point point = points.get(i);
			// Point point2 = points2.get(i - 1);
			// point2.x = (int) (point.x + fPoly.getX());
			// point2.y = (int) (point.y + fPoly.getY());
			// pApplet.ellipse(point.x, point.y, 10, 10);
			//
			// }
			// fPoly.postDraw(pApplet.g);
			// } else {
			// thing.setX((int) (x));
			// thing.setY((int) (y));
			// }
			//
			// }
			// }

			world.draw(pApplet);

			pApplet.ellipse(x, y, 25, 21);
		}
	}

	private void addBubble(PApplet pApplet) {

		float s = pApplet.random(20, 35);
		float x = pApplet.random(100, 900);

		 FBlob b = new FBlob();
		//FCircle b = new FCircle(s);
//		b.setPosition(x, pApplet.height - pApplet.random(100, 110));
		 b.setAsCircle(x, pApplet.height - pApplet.random(100, 110), s, 20);
		b.setStroke(0);
		b.setStrokeWeight(0);
		b
				.setFill(pApplet.random(255), pApplet.random(255), pApplet
						.random(255));
		world.add(b);
	}

	public void setup(PApplet pApplet) {
		// setup(pApplet, null);
	}

	public void setup(PApplet pApplet, GuiFactory guiFactory) {

		Fisica.init(pApplet);

		initFisica();
		this.pApplet = pApplet;
		// initControl(controlFacade);
		// world.setEdges();
		// world.remove(world.left);
		// world.remove(world.right);
		// world.remove(world.top);
		setTop(pApplet);

	}

	private void initFisica() {
		world = new FWorld(1024,768);
		world.setGravity(0, -300);
	}

	public void setTop(PApplet applet) {
		top = new FBox(applet.width, 20);
		top.setStaticBody(true);
		top.setGrabbable(false);
		top.setPosition(applet.width / 2, -5);
		top.setFillColor(0);
		top.setStrokeColor(0);

		world.addBody(top);
	}

	public void initControl(ControlFacade controlFacade) {

		// Slider slider = controlP5
		// .addSlider("density", 0, 50, 10, 0, 25, 35, 10);
		// int key = controlFacade.addController(slider);
		// controllers.put("density", density);
		//
		// Slider slider2 = controlP5.addSlider("restitutions", 0, 1, 10, 0, 40,
		// 35, 10);
		// int key2 = controlFacade.addController(slider2);
		// controllers.put("restitutions", restitutions);
		//
		// Radio r = controlP5.addRadio("isStatic", 0, 55);
		// r.deactivateAll(); // use deactiveAll to not make the first radio
		// button
		// // active.
		// r.add("true", 1);
		// r.add("false", 0);
		// r.activate("true");
		//
		// int key3 = controlFacade.addController(r);
		// controllers.put("isStatic", isStatic);

	}

	edu.maping.easy.gui.Button start = null;

	public void controlEvent(ControlEvent theEvent) {

		if (!theEvent.isGroup()) {
			Controller controller = theEvent.controller();
			String string = controller.name();
			Float value = controller.value();
			Float currentValue = controllers.get(string);
			if (currentValue == null)
				currentValue = value;
		}
	}

	public Thing newThing() {
		return new PhysicPolyThing(0, 0);
	}

	public void setParameters(Thing thing) {

		if (thing instanceof PhysicPolyThing) {
			PhysicPolyThing temp = (PhysicPolyThing) thing;
			temp.setDensity(density.intValue());
			temp.setRestitutions(restitutions);
		}

	}

	@Override
	public String getName() {
		return "fisica";
	}

	@Override
	public boolean mouseClicked(int mouseX, int mouseY, Thing newThing,
			MouseEvent mouseEvent) {

		return false;
	}

	@Override
	public void mouseDragged(int mouseX, int mouseY, Thing newThing) {
	}

	@Override
	public void mouseReleased(int mouseX, int mouseY, Thing newThing) {
	}

	@Override
	public void mousePreassed(int mouseX, int mouseY, Thing newThing) {
	}

	@Override
	public void stop(World world, PApplet pApplet, ControlP5 controlP5) {
		started = false;
		ArrayList<FBody> bodies = this.world.getBodies();
		// for (FBody fBody : bodies) {
		// this.world.removeBody(fBody);
		// }
		initFisica();
	}

	@Override
	public void editKeyPressed(int key, Thing thing) {
		// TODO Auto-generated method stub

	}

	@Override
	public void KeyPressed(KeyBoardInteraction key) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseWheelMoved(MouseWheelEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void controlEvent(GUIEvent event) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseMoved(int mouseX, int mouseY) {
		// TODO Auto-generated method stub

	}

}
